/**
  ******************************************************************************
  * @file    acad_driver.c
  * @author  Sherlock
  * @version V0.1
  * @date    08/2/2024
  * @brief   ACAD Handling
  ******************************************************************************
  * @copy
  *
  * <h2><center>&copy; COPYRIGHT 2010 Feirui</center></h2>
  */ 



/**
  * @brief  INCLUDE FILES.
  */
#ifndef	ACAD_DRIVER_GLOBALS
#define	ACAD_DRIVER_GLOBALS
#include <includes.h>
#include "acad_driver.h"
#include "acad_cfg.h"


static uint8_t ACAD_HWInit_RCC(void);
static uint8_t ACAD_HWInit_TIM(void);
static uint8_t ACAD_HWInit_GPIO(void);
static uint8_t ACAD_HWInit_DMA(void);
static uint8_t ACAD_HWInit_ADC(void);
static uint8_t ACAD_HWInit_NVIC(FunctionalState TIMCtrSta);


/* ACAD初始化函数 */
uint8_t ACAD_HWInit(void)
{
  uint8_t status = DEF_FALSE;

  status |= ACAD_HWInit_RCC();
	status |= ACAD_HWInit_TIM();
	status |= ACAD_HWInit_GPIO();
	status |= ACAD_HWInit_DMA();
	status |= ACAD_HWInit_ADC();
  status |= ACAD_HWInit_NVIC(ENABLE);

  return status;
}


/* ACAD使能，开始工作 */
uint8_t ACAD_HWEnable(void)
{
  /* ENABLE ADC1 */
  ADC_Enable(ADC1, ENABLE);
  /* ENABLE ADC2 */
  ADC_Enable(ADC2, ENABLE);

  /* Enable ADC1 external trigger */ 
  ADC_EnableExternalTrigConv(ADC1, ENABLE);
  /* Enable the CCx Interrupt Request */
  DMA_ConfigInt(ACAD_DMA_Channel,ACAD_DMA_Channel_IT, ENABLE);

  /* Timer Start */
  TIM_Enable(ADCSampleTIMx, ENABLE);

  return DEF_TRUE;
}


static uint8_t ACAD_HWInit_RCC(void)
{
  RCC_EnableAPB1PeriphClk(ADCSampleTIMx_RCCPeriph, ENABLE);  //使能TIM3时钟作为ADC采样触发源

  /* Set ADCCLK */
  RCC_ConfigAdc1mClk(RCC_ADC1MCLK_SRC_HSE, RCC_ADC1MCLK_DIV8);
	ADC_ConfigClk(ADC_CTRL3_CKMOD_AHB, RCC_ADCHCLK_DIV4);
	
  /* Enable DMA, ADC clock */
  RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_DMA1, ENABLE);
  RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_ADC1 | RCC_AHB_PERIPH_ADC2, ENABLE);
	
  /* Enable GPIOx clock */
	uint32_t RCC_APBxPeriph_GPIOx;
  uint8_t i;
  for(i = 0, RCC_APBxPeriph_GPIOx = 0; i < ACADCPortCfgNumber; i++)
    RCC_APBxPeriph_GPIOx |= ACADCPortCfgTbl[i].RCC_APB2Periph;
  RCC_EnableAPB2PeriphClk(RCC_APBxPeriph_GPIOx, ENABLE);

	return DEF_TRUE;
}


/* 选定TIM3触发作为ADC采样触发时钟，周期10kHz */
static uint8_t ACAD_HWInit_TIM(void)
{
  TIM_TimeBaseInitType TIM_TimeBaseStructure;
  
  /* Disable TIM counter */
  TIM_Enable(ADCSampleTIMx, DISABLE);
  /* Clear TIM Flag */
  TIM_ClearFlag(ADCSampleTIMx, ADCSampleTIMx_FLAGx);
  /* Clear TIM Pending Bit */
  TIM_ClrIntPendingBit(ADCSampleTIMx, ADCSampleTIMx_ITx);
  /* Choose Internal Clock */
  TIM_ConfigInternalClk(ADCSampleTIMx);

  /* Time Base configuration */
  TIM_TimeBaseStructure.Prescaler = ADCSampleTIMx_Prescaler        ;
  TIM_TimeBaseStructure.CntMode   = ADCSampleTIMx_CounterMode      ;
  TIM_TimeBaseStructure.Period    = ADCSampleTIMx_Period           ;
  TIM_TimeBaseStructure.ClkDiv    = ADCSampleTIMx_ClockDivision    ;
  TIM_TimeBaseStructure.RepetCnt  = ADCSampleTIMx_RepetitionCounter;
  TIM_InitTimeBase(ADCSampleTIMx, &TIM_TimeBaseStructure);
  /* 选择触发源 */
  TIM_SelectOutputTrig(ADCSampleTIMx, TIM_TRGO_SRC_UPDATE);

	return DEF_TRUE;
}


static uint8_t ACAD_HWInit_GPIO(void)
{
  GPIO_InitType GPIO_InitStructure;
	
  /* Configuration Port for ADC pin */
	GPIO_InitStruct(&GPIO_InitStructure);
  for(uint8_t i = 0; i < ACADCPortCfgNumber; i++)
  {
    GPIO_InitStructure.Pin = ACADCPortCfgTbl[i].GPIO_Pin;
    GPIO_InitStructure.GPIO_Speed = ACADCPortCfgTbl[i].GPIO_Speed;
    GPIO_InitStructure.GPIO_Mode  = ACADCPortCfgTbl[i].GPIO_Mode;
    GPIO_InitPeripheral(ACADCPortCfgTbl[i].GPIOx, &GPIO_InitStructure);
  }

#ifdef CalTime_Enable
	/* 测试计算时间 */
  RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOC, ENABLE);
	GPIO_InitStructure.Pin   = GPIO_PIN_13;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_Out_PP;
	GPIO_InitPeripheral(GPIOC, &GPIO_InitStructure);
#endif

	return DEF_TRUE;
}


static uint8_t ACAD_HWInit_DMA(void)
{
  DMA_InitType DMA_InitStructure;

  /* DMAx channelx configuration ----------------------------------------------*/
  DMA_InitStructure.PeriphAddr        = ACAD_DMA_PeripheralBaseAddr; //外设为ADC
  DMA_InitStructure.MemAddr           = ACBufferArea1Address[ACMeasureBufferAreaNum % ADCBufferAreaNum]; //指定存储器的首地址
  DMA_InitStructure.Direction         = ACAD_DMA_DIR               ; //指定方向为外设到存储器
  DMA_InitStructure.BufSize        		= ACAD_DMA_BufferSize        ; //指定DMA的缓存规格为3000个4B，
  DMA_InitStructure.PeriphInc      		= ACAD_DMA_PeripheralInc     ; //指定外设和存储器都为自增
  DMA_InitStructure.DMA_MemoryInc     = ACAD_DMA_MemoryInc         ;
  DMA_InitStructure.PeriphDataSize 		= ACAD_DMA_PeripheralDataSize; //指定外设为16位（word）宽度，因为每次采集都是ADC1和ADC2同时采集，每个ADC结果都是16bit（实际只有12bit有效）
  DMA_InitStructure.MemDataSize    	  = ACAD_DMA_MemoryDataSize    ; //指定存储器为16位（word）宽度
  DMA_InitStructure.CircularMode      = ACAD_DMA_Mode              ; //指定为循环模式
  DMA_InitStructure.Priority          = ACAD_DMA_Priority          ; //设定高优先级
  DMA_InitStructure.Mem2Mem           = ACAD_DMA_M2M               ;
  DMA_Init(ACAD_DMA_Channel, &DMA_InitStructure);
	/* Enable the CCx Interrupt Request */
  DMA_ConfigInt(ACAD_DMA_Channel,ACAD_DMA_Channel_IT, ENABLE);
  /* Enable DMAx Channelx */
  DMA_EnableChannel(ACAD_DMA_Channel, ENABLE);

	return DEF_TRUE;
}


static uint8_t ACAD_HWInit_ADC(void)
{
	ADC_InitType ADC_InitStructure;
  
  /*Reset ADC && DMA*/
  // Reset_Cfg3DMA_ADC();

  /* ADC1 configuration ------------------------------------------------------*/
  ADC_InitStructure.WorkMode         = ACAD_ADC1_Mode              ; //同步规则转换
  ADC_InitStructure.MultiChEn        = ACAD_ADC1_MultiChannel      ; //多通道转换
  ADC_InitStructure.ContinueConvEn   = ACAD_ADC1_ContinuousConvMode; //不连续转换
  ADC_InitStructure.ExtTrigSelect    = ACAD_ADC1_ExternalTrigConv  ; //选择定时器3的触发源作为转换外部触发 ADC_EXT_TRIGCONV_T3_TRGO
  ADC_InitStructure.DatAlign         = ACAD_ADC1_DataAlign         ; //右对齐
  ADC_InitStructure.ChsNumber        = ACAD_ADC1_NbrOfChannel      ; //5个采样通道
  ADC_Init(ADC1, &ADC_InitStructure);
  /* ADC regular channels configuration 设置每个通道的物理通道号，取样顺序，取样时间 */
  for(uint8_t i=0; i < ACAD_ADC1_NbrOfChannel; i++)
    ADC_ConfigRegularChannel(ADC1, ADC1RegularTbl[i].ADC_Channel, ADC1RegularTbl[i].Rank, ADC1RegularTbl[i].ADC_SampleTime);
  /* Enable ADC1 DMA */
  ADC_EnableDMA(ADC1, ENABLE);

  /* ADC1 configuration ------------------------------------------------------*/
  ADC_InitStructure.WorkMode         = ACAD_ADC2_Mode              ; //同步规则转换
  ADC_InitStructure.MultiChEn        = ACAD_ADC2_MultiChannel      ; //多通道转换
  ADC_InitStructure.ContinueConvEn   = ACAD_ADC2_ContinuousConvMode; //不连续转换
  ADC_InitStructure.ExtTrigSelect    = ACAD_ADC2_ExternalTrigConv  ; //选择定时器3的触发源作为转换外部触发 ADC_EXT_TRIGCONV_T3_TRGO
  ADC_InitStructure.DatAlign         = ACAD_ADC2_DataAlign         ; //右对齐
  ADC_InitStructure.ChsNumber        = ACAD_ADC2_NbrOfChannel      ; //5个采样通道
  ADC_Init(ADC2, &ADC_InitStructure);
  /* ADC regular channels configuration 设置每个通道的物理通道号，取样顺序，取样时间 */
  for(uint8_t i=0; i < ACAD_ADC2_NbrOfChannel; i++)
    ADC_ConfigRegularChannel(ADC2, ADC2RegularTbl[i].ADC_Channel, ADC2RegularTbl[i].Rank, ADC2RegularTbl[i].ADC_SampleTime);
  /* Enable ADC2 external trigger conversion */
  ADC_EnableExternalTrigConv(ADC2, ENABLE);

  /* ADC1 Calib */
  ADC_Enable(ADC1, ENABLE);
  while(ADC_GetFlagStatusNew(ADC1, ADC_FLAG_RDY) == RESET);
  /* Start ADC1 calibaration */
  ADC_StartCalibration(ADC1);
  /* Check the end of ADC1 calibration */
  while(ADC_GetCalibrationStatus(ADC1));
  /* Disable ADC1 */
  ADC_Enable(ADC1, DISABLE);

  /* ADC2 Calib */
  ADC_Enable(ADC2, ENABLE);
  while(ADC_GetFlagStatusNew(ADC2, ADC_FLAG_RDY) == RESET);
  /* Start ADC2 calibaration */
  ADC_StartCalibration(ADC2);
  /* Check the end of ADC2 calibration */
  while(ADC_GetCalibrationStatus(ADC2));
  /* Disable ADC2 */
  ADC_Enable(ADC2, DISABLE);

	return DEF_TRUE;
}


/* NVIC configuration */
static uint8_t ACAD_HWInit_NVIC(FunctionalState TIMCtrSta)
{
  NVIC_InitType NVIC_InitStructure;
  
  /* Enable the DMA1 TX Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel                   = ACAD_NVIC_IRQChannel;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = ACAD_NVIC_IRQPrePrio;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority        = ACAD_NVIC_IRQSubPrio;
  NVIC_InitStructure.NVIC_IRQChannelCmd                = TIMCtrSta;
  NVIC_Init(&NVIC_InitStructure);

  return DEF_TRUE;
}



#endif	/*	ACAD_DRIVER_GLOBALS	*/

/******************* (C) COPYRIGHT 2010 Feirui *****END OF FILE****/